package com.dc.schedule.spring;


import com.dc.schedule.client.socket.ScheduleSocketClient;
import com.dc.schedule.client.socket.SimpleScheduleSocketClient;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.StringUtils;

import java.util.concurrent.ExecutorService;

@AutoConfiguration
@EnableConfigurationProperties(ScheduleClientConfig.class)
@RequiredArgsConstructor
@ConditionalOnProperty(value = "schedule.client.enabled", havingValue = "true", matchIfMissing = true)
public class ScheduleClientAutoConfiguration implements ApplicationContextAware {
    private final ScheduleClientConfig scheduleClientConfig;
    
    @Setter
    private ApplicationContext applicationContext;
    
    @Bean
    @ConditionalOnMissingBean
    public ScheduleSocketClient scheduleSocketClient() {
        return new SimpleScheduleSocketClient();
    }
    
    
    @Bean
    @Qualifier("scheduleClientTaskExecutor")
    @ConditionalOnProperty(value = "schedule.client.custom-executor-service-bean-name", matchIfMissing = true)
    public ThreadPoolTaskExecutor scheduleClientTaskExecutor() {
        final TaskExecutionProperties.Pool pool = scheduleClientConfig.getPool();
        final TaskExecutionProperties.Shutdown shutdown = scheduleClientConfig.getShutdown();
        TaskExecutorBuilder builder = new TaskExecutorBuilder();
        builder = builder.queueCapacity(pool.getQueueCapacity());
        builder = builder.corePoolSize(pool.getCoreSize());
        builder = builder.maxPoolSize(pool.getMaxSize());
        builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
        builder = builder.keepAlive(pool.getKeepAlive());
        builder = builder.awaitTermination(shutdown.isAwaitTermination());
        builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
        builder = builder.threadNamePrefix("sc-task-");
        return builder.build();
    }
    
    
    @Bean
    public ScheduleClientBeanPostProcessor scheduleClientBeanPostProcessor(ScheduleSocketClient scheduleSocketClient) {
        
        
        final ScheduleClientBeanPostProcessor processor = new ScheduleClientBeanPostProcessor();
        processor.setClientConfig(scheduleClientConfig);
        processor.setSocketClient(scheduleSocketClient);
        final String beanName = StringUtils.hasText(scheduleClientConfig.getCustomExecutorServiceBeanName()) ?
                                        scheduleClientConfig.getCustomExecutorServiceBeanName() :
                                        "scheduleClientTaskExecutor";
        Object executor = applicationContext.getBean(
                beanName
        );
        if (executor instanceof ThreadPoolTaskExecutor) {
            processor.setExecutorService(((ThreadPoolTaskExecutor) executor).getThreadPoolExecutor());
        } else if (executor instanceof ExecutorService) {
            processor.setExecutorService((ExecutorService) executor);
        } else {
            throw new IllegalStateException("bean name [" + beanName + "] 无法识别为线程池类型！实际类型：" + executor.getClass());
        }
        return processor;
    }
}
